
package com.hlkj.pay.app.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import com.hlkj.framework.caches.service.RedisTemplateService;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.IMerchantConfigAppService;
import com.hlkj.pay.app.merchant.ext.dto.profit.ChannelProfitOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.alipay.dto.AliComplaintNotifyResp;
import com.hlkj.pay.app.merchant.ext.impl.alipayZft.dto.AlipayZftDivideNotifyBizContentDto;
import com.hlkj.pay.app.merchant.impl.CommonChannelCallHandler;
import com.hlkj.pay.app.order.IComplaintOrderAppService;
import com.hlkj.pay.app.order.IPayOrderAppService;
import com.hlkj.pay.app.order.IRefundOrderAppService;
import com.hlkj.pay.app.order.constant.OrderConstant;
import com.hlkj.pay.app.transfer.PayOrderDoToResp;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.common.OpenApiResultCode;
import com.hlkj.pay.common.PayResultCode;
import com.hlkj.pay.dto.LocalMerchantRequest;
import com.hlkj.pay.dto.common.OrderStatusDto;
import com.hlkj.pay.dto.merchant.MerchantLimitPaymentDto;
import com.hlkj.pay.dto.merchant.RouterResultDto;
import com.hlkj.pay.dto.order.*;
import com.hlkj.pay.dto.order.notify.CsOrderNotifyDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.order.IChannelPayOrderGateway;
import com.hlkj.pay.gateway.profit.IChannelProfitOrderGateway;
import com.hlkj.pay.infrastructure.model.common.CommonAppDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessAuthDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantInfoDO;
import com.hlkj.pay.infrastructure.model.order.OrderComplaintDO;
import com.hlkj.pay.infrastructure.model.order.OrderFundDetailDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.service.merchant.IMerchantConfigService;
import com.hlkj.pay.service.merchant.IMerchantService;
import com.hlkj.pay.service.order.IOrderComplaintService;
import com.hlkj.pay.service.order.IPayOrderFundService;
import com.hlkj.pay.service.order.IPayOrderService;
import com.hlkj.pay.service.pay.IPayChannelService;
import com.hlkj.pay.service.pay.IPayWayService;
import com.hlkj.pay.service.pay.IProviderService;
import com.hlkj.pay.task.AdPayOrderScheduledTasks;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.openapi.order.req.PayOrderQueryReq;
import com.hlkj.pay.vo.openapi.order.resp.PayOrderSubmitApiResp;
import com.hlkj.pay.vo.order.req.OrderAccount;
import com.hlkj.pay.vo.order.req.PayOrderParamReq;
import com.hlkj.pay.vo.order.req.PreOrderPayReq;
import com.hlkj.pay.vo.order.resp.PayOrderResp;
import com.hlkj.pay.vo.order.resp.PrePayOrderResp;
import com.hlkj.pay.vo.order.resp.acct.PayOrderFundResp;
import com.ijpay.alipay.AliPayApi;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/09 17:55
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Validated
public class PayOrderAppServiceImpl implements IPayOrderAppService {

    private final IPayWayService payWayService;

    private final MerchantChannelRouteHandler merchantChannelRouteHandler;

    private final IPayOrderService payOrderService;

    private final OrderHandler orderHandler;

    private final OrderCodeUtil orderCodeUtil;

    private final IProviderService providerService;

    private final IPayChannelService payChannelService;

    private final CommonChannelCallHandler commonChannelCallHandler;

    private final IRefundOrderAppService refundOrderAppService;

    private final IChannelPayOrderGateway channelOrderGateway;

    private final IChannelProfitOrderGateway channelProfitOrderGateway;

    private final IMerchantService merchantService;

    private final IMerchantApplicationService merchantApplicationService;

    private final IMerchantConfigService merchantConfigService;

    private final IComplaintOrderAppService complaintOrderAppService;

    private final  IOrderComplaintService orderComplaintService;

    @Value("${rocketmq.consumer.order_delay_consumer_count:5}")
    private Integer orderDelayConsumerCount;

    private final IPayOrderFundService payOrderFundService;

    private final IMerchantConfigAppService merchantConfigAppService;

    private final AdPayOrderScheduledTasks adPayOrderScheduledTasks;

    @Value("${hlkj.defaultRedirectUrl}")
    private String defaultRedirectUrl;

    private final RedisTemplateService redisTemplateService;

    @Override
    public CommonResult<PayOrderSubmitApiResp> submitOrder(@Valid PayOrderParamReq payOrderParamReq) {
        // 获取支付方式
        PayWayDO payWayDO = null;
        // 自有充值都是传 payWayCode
        LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
        String orderSn = null;
        if (StringUtils.hasText(localMerchantRequest.getSubSn())) {
            orderSn = localMerchantRequest.getSubSn();
        }
        else {
            orderSn = localMerchantRequest.getSn();
        }
        boolean isValid = ReUtil.isMatch("^[\\w]+$", payOrderParamReq.getMchOrderNo());
        if (!isValid) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FORMAT_EXIST);
        }

        PayOrderDO existPayOrder = payOrderService.queryPayOrderByMerOrderNo(orderSn, payOrderParamReq.getMchOrderNo());

        if (existPayOrder != null) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_EXIST);
        }
        if (StringUtils.hasText(payOrderParamReq.getPayWayCode())) {
            payWayDO = payWayService.queryByCode(payOrderParamReq.getPayWayCode());
        }
        else {
            PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByType(payOrderParamReq.getPayType());
            if (payType == null) {
                log.info("提交的支付类型错误:{}", payOrderParamReq.getPayType());
                return CommonResult.error(OpenApiResultCode.PAY_WAY_NOT_EXITS);
            }
            PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.fromByType(payOrderParamReq.getPaySubType());
            if (scenePayType == null) {
                log.info("提交的支付方式错误:{}", payOrderParamReq.getPaySubType());
                return CommonResult.error(OpenApiResultCode.PAY_WAY_NOT_EXITS);
            }
            Integer sceneType = payOrderParamReq.getSceneType();
            if (sceneType == null) {
                payOrderParamReq.setSceneType(PayEnums.SCENE_TYPE.OFFLINE.getCode());
            }
            // 获取支付方式
            payWayDO = payWayService.queryByType(payType.getCode(), scenePayType, payOrderParamReq.getSceneType());
        }
        if (payWayDO == null || StrUtil.isEmpty(payWayDO.getSubType())) {
            return CommonResult.error(OpenApiResultCode.PAY_WAY_NOT_EXITS);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(payWayDO.getStatus())) {
            return CommonResult.error(OpenApiResultCode.PAY_WAY_NOT_EFFECT);
        }
        if (payOrderParamReq.getFundProcessType() != null) {
            // 分账类型校验
            PayOrderEnums.FUND_PROCESS_TYPE fundProcessType = PayOrderEnums.FUND_PROCESS_TYPE.from(payOrderParamReq.getFundProcessType());
            if(fundProcessType == null){
                return CommonResult.error(OpenApiResultCode.MERCHANT_ACCT_TYPE_NOT_EXIST);
            }

            if (PayOrderEnums.FUND_PROCESS_TYPE.REAL_TIME.getCode().equals(payOrderParamReq.getFundProcessType()) && CollectionUtils.isEmpty(payOrderParamReq.getAcctInfos())) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
            }
            // 无分账 商户默认分账 不接收分账信息
            if (PayOrderEnums.FUND_PROCESS_TYPE.NO.getCode().equals(payOrderParamReq.getFundProcessType())
                    || PayOrderEnums.FUND_PROCESS_TYPE.MERCHANT.getCode().equals(payOrderParamReq.getFundProcessType())) {
                payOrderParamReq.setAcctInfos(null);
            }
            if (!CollectionUtils.isEmpty(payOrderParamReq.getAcctInfos())) {
                double summed = payOrderParamReq.getAcctInfos().stream().mapToDouble(acctInfo -> MerchantUtils.stringToBigDecimal(acctInfo.getAmount()).doubleValue()).sum();
                if (MerchantUtils.doubleToBigDecimal(summed).compareTo(MerchantUtils.stringToBigDecimal(payOrderParamReq.getAmount())) > 0) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
                }
                Set<String> accountNos = payOrderParamReq.getAcctInfos().stream().map(acctInfo -> acctInfo.getAccountNo()).collect(Collectors.toSet());
                if (accountNos.size() != payOrderParamReq.getAcctInfos().size()) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_FUND_DATA_ERROR);
                }
            }
        }
        else {
            payOrderParamReq.setAcctInfos(null);
            // payOrderParamReq.setFundProcessType(PayOrderEnums.FUND_PROCESS_TYPE.NO.getCode());
            payOrderParamReq.setFundProcessType(null);
        }
        switch (PayEnums.SCENE_PAY_TYPE.fromByType(payWayDO.getSubType())) {
            case SCAN:
                if (payOrderParamReq.getExtra() == null || !StringUtils.hasText(payOrderParamReq.getExtra().getAuthCode())) {
                    return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
                }
        }
        // 交易费率
        MerchantInfoDO merchantInfoDO = merchantService.queryMerchant(orderSn);
        // 外扣手续费率
        BigDecimal commRateBase = merchantInfoDO.getCommRateBase();
        if (commRateBase == null) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_COMM_RATE_BASE_EXIST);
        }

        BigDecimal orderAmount = new BigDecimal(payOrderParamReq.getAmount());
        BigDecimal feeAmount = new BigDecimal(0);
        if (merchantInfoDO.getProfitSharingRule() != null && merchantInfoDO.getProfitSharingRule() != 2) {
            // 外扣手续费
            feeAmount = MerchantUtils.calculateFeeUp(orderAmount, commRateBase);
            // 余额是否拦截
            if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantInfoDO.getBlockBal())) {
                BigDecimal merchantFeeAmount = merchantService.queryMerchantFeeAmount(orderSn);
                if (merchantFeeAmount == null || merchantFeeAmount.compareTo(feeAmount) < 0) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_CHANNEL_BALANCE_NOT_ENOUGH);
                }
            }
        }

        MerchantLimitPaymentDto merchantLimitPaymentDto = merchantConfigAppService.queryLimitConfig(merchantInfoDO.getSn());

        //交易限额
        if (merchantLimitPaymentDto != null && merchantLimitPaymentDto.getLimitState() != null && CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantLimitPaymentDto.getLimitState())) {
            //单笔交易额
            if (merchantLimitPaymentDto.getLimitPayAmount() != null) {
                if (orderAmount.compareTo(merchantLimitPaymentDto.getLimitPayAmount()) > 0) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_LIMIT_AMOUNT);
                }
            }

            //校验日交易额
            if (merchantLimitPaymentDto.getLimitAmount() != null) {
                PayOrderQueryDto payOrderQueryDto = new PayOrderQueryDto();
                payOrderQueryDto.setSn(merchantInfoDO.getSn());
                String day = DateUtils.getDateString(DatePattern.NORM_DATE_PATTERN);
                payOrderQueryDto.setStartQueryTime(DateUtils.shanghaiStartDate(day, DatePattern.NORM_DATE_PATTERN));
                payOrderQueryDto.setEndQueryTime(DateUtils.shanghaiEndDate(day, DatePattern.NORM_DATE_PATTERN));
                payOrderQueryDto.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                RouterOrderDataDto routerOrderDataDto = payOrderService.querySuccessOrderAmount(payOrderQueryDto);
                if (routerOrderDataDto != null && routerOrderDataDto.getSuccessOrderAmount() != null && routerOrderDataDto.getSuccessOrderAmount().compareTo(merchantLimitPaymentDto.getLimitAmount()) > 0) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_LIMIT_DAY_AMOUNT);
                }
            }

            //校验月交易额
            if (merchantLimitPaymentDto.getLimitMonthAmount() != null) {
                PayOrderQueryDto payOrderQueryDto = new PayOrderQueryDto();
                payOrderQueryDto.setSn(merchantInfoDO.getSn());
                String day = DateUtils.getDateString(DatePattern.NORM_DATE_PATTERN);
                String sday = DateUtils.offsetDay(day, DatePattern.NORM_DATE_PATTERN, -30);
                payOrderQueryDto.setStartQueryTime(DateUtils.shanghaiStartDate(sday, DatePattern.NORM_DATE_PATTERN));
                payOrderQueryDto.setEndQueryTime(DateUtils.shanghaiEndDate(day, DatePattern.NORM_DATE_PATTERN));
                payOrderQueryDto.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                RouterOrderDataDto routerOrderDataDto = payOrderService.querySuccessOrderAmount(payOrderQueryDto);
                if (routerOrderDataDto != null && routerOrderDataDto.getSuccessOrderAmount() != null && routerOrderDataDto.getSuccessOrderAmount().compareTo(merchantLimitPaymentDto.getLimitMonthAmount()) > 0) {
                    return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_LIMIT_MONTH_AMOUNT);
                }
            }
        }

        // 支付通道路由
        CommonResult<RouterResultDto> merchantAppChannelDOCommonResult = merchantChannelRouteHandler.merchantChannelRoute(payOrderParamReq.getProviderCode(),
                payOrderParamReq.getChannelCode(), payOrderParamReq.getMchChannelCode(), orderAmount,payWayDO);
        if (!merchantAppChannelDOCommonResult.isSuccess()) {
            return CommonResult.error(merchantAppChannelDOCommonResult.getCode(), merchantAppChannelDOCommonResult.getMsg());
        }
        RouterResultDto routerResultDto = merchantAppChannelDOCommonResult.getData();
        MerchantAppChannelDO merchantAppChannelDO = routerResultDto.getMerchantAppChannel();
        MerchantAccessAuthDO merchantAccessAuth = routerResultDto.getMerchantAccessAuth();
        boolean extensionExist = channelOrderGateway.extensionExist(merchantAppChannelDO.getChannelCode());
        if (!extensionExist) {
            return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
        }
        // 将通道的分账方式 同步到订单
        if (payOrderParamReq.getFundProcessType() == null) {
            if (merchantAppChannelDO.getFundProcessType() == null) {
                payOrderParamReq.setFundProcessType(PayOrderEnums.FUND_PROCESS_TYPE.NO.getCode());
            }
            else {
                payOrderParamReq.setFundProcessType(merchantAppChannelDO.getFundProcessType());
            }
        }

        String payOrderNo = null;
        // 生成订单对象
        PayOrderDO payOrderDO = buildPayOrder(payWayDO, merchantAppChannelDO, payOrderParamReq, payOrderNo, orderSn, commRateBase, feeAmount);
        if (merchantAccessAuth != null) {
            payOrderDO.setAutCode(merchantAccessAuth.getCode());
        }
        // 订单号生成 部分渠道 的支付场景 订单号有特殊要求
        CommonResult<String> commonResult = channelOrderGateway.channelOrderCode(payOrderDO);
        if (!commonResult.isSuccess()) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_TERM_FAIL.getCode(), commonResult.getMsg());
        }
        payOrderNo = commonResult.getData();
        if (!StringUtils.hasText(payOrderNo)) {
            // 订单号生成
            payOrderNo = orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.ORDER);
            if (!StringUtils.hasText(payOrderNo)) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_OPERATE_FAIL);
            }
        }
        payOrderDO.setPayOrderNo(payOrderNo);
        if (!CollectionUtils.isEmpty(payOrderParamReq.getAcctInfos())) {
            List<PayOrderFundDto> payOrderFundDtoList = new ArrayList<>();
            String batchNo = IdUtils.getSnowflakeNextIdStr();
            int i = 1;
            for (OrderAccount orderAccount : payOrderParamReq.getAcctInfos()) {
                PayOrderFundDto payOrderFundDto = BeanUtil.copyProperties(orderAccount, PayOrderFundDto.class);
                payOrderFundDto.setBatchNo(batchNo);
                payOrderFundDto.setBatchNoDetail(batchNo + "_" + i);
                i = i + 1;
                payOrderFundDtoList.add(payOrderFundDto);
            }
            payOrderDO.setAcctInfoJson(JsonUtils.toJsonStringNotNull(payOrderFundDtoList));
        }

        // 营销信息转成json入库
        if(payOrderParamReq.getMarketInfo() != null){
            payOrderDO.setMarketingOrdersJson(JsonUtils.toJsonStringNotNull(payOrderParamReq.getMarketInfo()));
        }

        if (payOrderParamReq.getMarketProcessType() != null) {
            payOrderDO.setMarketProcessType(payOrderParamReq.getMarketProcessType());
        }

        payOrderDO.setAuthCode(payOrderParamReq.getAuthCode());

        // 获取锁
        RLock rLock = redisTemplateService.getLock("order:submitOrder:"+payOrderDO.getMchOrderNo());
        // 返回参数填充
        PayOrderSubmitApiResp payOrderResp = null;
        try {
            // 获取锁成功，处理业务
            if (!rLock.tryLock(0,30, TimeUnit.SECONDS)) {
                log.info("submitChannelPayOrder tryLock fail, payOrderDO:{}", JSONUtil.toJsonStr(payOrderDO));
                return CommonResult.error(0,"已提交订单,请务重复提交");
            }
            PayOrderChannelResultDto payOrderChannelResultDto = channelOrderGateway.submitChannelPayOrder(payOrderDO);
            // 返回参数填充
            payOrderResp = buildThirdOrderParams(payOrderDO, payOrderChannelResultDto);
            if (!payOrderChannelResultDto.isProcessStatus()) {
                payOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.FAIL.getCode());
                if(StrUtil.isEmpty(payOrderChannelResultDto.getRemark())){
                    log.info("submitChannelPayOrder 提交支付未返回错误, payOrderParamReq:{}, payOrderDO:{}", JSONUtil.toJsonStr(payOrderParamReq),JSONUtil.toJsonStr(payOrderDO));
                    payOrderDO.setBankMsg("未知错误");
                }else{
                    payOrderDO.setBankMsg(payOrderChannelResultDto.getRemark());
                }
                // 下单失败通道路由
                if(payOrderChannelResultDto.isRequestChannel()){
                    adPayOrderScheduledTasks.merchantChannelRoute(payOrderDO,payWayDO,merchantAccessAuth,localMerchantRequest.getSn(), localMerchantRequest.getMerchantAppDO());
                }
            }
            payOrderService.addPayOrder(payOrderDO);
            if (!payOrderChannelResultDto.isProcessStatus()) {
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_OPERATE_FAIL.getCode(), payOrderChannelResultDto.getRemark());
            }
            if (StringUtils.hasText(payOrderDO.getAcctInfoJson())) {
                List<PayOrderFundDto> payOrderFundDtos = JsonUtils.parseArray(payOrderDO.getAcctInfoJson(), PayOrderFundDto.class);
                payOrderFundService.addAcctPayInfo(null, payOrderFundDtos, payOrderDO);
            }
            // 统计数据
            orderHandler.submitPayOrder(payOrderDO);
        }
        catch (Exception e) {
            log.error("submitChannelPayOrder fail,errMsg:{}",e);
            return CommonResult.error(0,"下单失败,errMsg:"+e.getMessage());
        } finally {
            //释放锁
            rLock.forceUnlock();
        }
        // 返回支付数据
        return CommonResult.success(payOrderResp);
    }

    @Override
    public CommonResult<PayOrderResp> preSubmitOrder(PreOrderPayReq preOrderPayReq) {
        // 订单查询
        PayOrderDO payOrderDO = payOrderService.queryPayOrder(preOrderPayReq.getPayOrderNo());
        if (payOrderDO == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_NOT_EXIST);
        }
        // 预下单
        payOrderDO.setPre(true);
        PayOrderEnums.PAY_ORDER_STATUS from = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (from) {
            case SUCCESS:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_SUCCESS);
            case CANCEL:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_CANCEL);
            case CLOSE:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_CLOSE);
            case FAIL:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_FAIL);
            case PAYING:
                PayOrderResp payOrderResp = PayOrderDoToResp.INSTANCE.payOrderResp(payOrderDO);
                PayOrderChannelResultDto payOrderChannelResultDto = payInfo(payOrderDO.getPayOrderNo());
                if (payOrderChannelResultDto != null) {
                    payOrderResp.setPayInfo(payOrderChannelResultDto.getPayInfo());
                    payOrderResp.setPayDataType(payOrderChannelResultDto.getPayDataType());
                }
                return CommonResult.success(payOrderResp);
        }
        PayWayDO payWayDO = payWayService.queryByCode(payOrderDO.getPayWayCode());
        boolean extensionExist = channelOrderGateway.extensionExist(payOrderDO.getChannelCode());
        if (!extensionExist) {
            return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
        }
        String channelPayCode = channelOrderGateway.channelPayCode(payOrderDO.getChannelCode(), payWayDO);
        if (!StringUtils.hasText(channelPayCode)) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_WAY_NOT_EFFECT);
        }
        payOrderDO.setAuthCode(preOrderPayReq.getAuthCode());
        PayOrderChannelResultDto payOrderChannelResultDto = channelOrderGateway.submitChannelPayOrder(payOrderDO);
        // 赋值 外层使用
        payOrderDO.setChannelOrderNo(payOrderChannelResultDto.getChannelOrderNo());
        payOrderDO.setInsOrderNo(payOrderChannelResultDto.getInsOrderNo());
        payOrderDO.setPayInfo(payOrderChannelResultDto.getPayInfo());
        payOrderDO.setPayDataType(payOrderChannelResultDto.getPayDataType());
        PayOrderDO updatePayOrderDO = buildPreThirdOrderParams(payOrderDO, payOrderChannelResultDto);
        if (!payOrderChannelResultDto.isProcessStatus()) {
            updatePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.FAIL.getCode());
            updatePayOrderDO.setBankMsg(payOrderChannelResultDto.getRemark());
        }
        payOrderDO.setExtra(JsonUtils.toJsonStringNotNull(payOrderChannelResultDto.getExtra()));
        String sn = payOrderDO.getSn();
        payOrderService.updatePayOrder(updatePayOrderDO, payOrderDO.getPayOrderNo(), sn, payOrderDO.getMchOrderNo());
        if (!payOrderChannelResultDto.isProcessStatus()) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_FAIL.getCode(), payOrderChannelResultDto.getRemark());
        }
        // 路由消息
        orderHandler.sendRouterMessage(payOrderDO);
        PayOrderResp payOrderResp = PayOrderDoToResp.INSTANCE.payOrderResp(payOrderDO);
        // 返回支付数据
        return CommonResult.success(payOrderResp);
    }

    private PayOrderChannelResultDto payInfo(String payOrderNo) {
        PayChannelRequestDO payChannelRequestDO = payChannelService.queryRequestByRelationId(payOrderNo, PayEnums.CHANNEL_REQUEST_TYPE.PAY_ORDER);
        return channelOrderGateway.payInfoParse(payChannelRequestDO);
    }

    @Override
    public CommonResult<PayOrderResp> queryOrder(PayOrderQueryReq payOrderQueryReq) {
        if (!StringUtils.hasText(payOrderQueryReq.getPayOrderNo()) && !StringUtils.hasText(payOrderQueryReq.getMchOrderNo())) {
            return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
        }
        PayOrderDO payOrderDO = null;
        if (StringUtils.hasText(payOrderQueryReq.getPayOrderNo())) {
            payOrderDO = payOrderService.queryPayOrder(payOrderQueryReq.getPayOrderNo());
        }
        else {
            String sn = LocalContext.get().getSn();
            payOrderDO = payOrderService.queryPayOrderByMerOrderNo(sn, payOrderQueryReq.getMchOrderNo());
        }
        if (payOrderDO == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_NOT_EXIST);
        }
        queryPayStatus(payOrderDO);
        PayOrderResp payOrderResp = PayOrderDoToResp.INSTANCE.payOrderResp(payOrderDO);
        if (StringUtils.hasText(payOrderDO.getAcctInfoJson())) {
            List<OrderFundDetailDO> payOrderFundList = payOrderFundService.queryPayAcctInfo(payOrderDO.getPayOrderNo());
            if (!CollectionUtils.isEmpty(payOrderFundList)) {
                List<PayOrderFundResp> payOrderFundResps = BeanUtil.copyToList(payOrderFundList, PayOrderFundResp.class);
                payOrderResp.setAcctInfos(JsonUtils.toJsonStringNotNull(payOrderFundResps));
            }
        }
        // 返回支付数据
        return CommonResult.success(payOrderResp);
    }

    @Override
    public CommonResult<Void> closeOrder(PayOrderQueryReq payOrderQueryReq) {
        if (!StringUtils.hasText(payOrderQueryReq.getPayOrderNo()) && !StringUtils.hasText(payOrderQueryReq.getMchOrderNo())) {
            return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
        }
        PayOrderDO payOrderDO = null;
        if (StringUtils.hasText(payOrderQueryReq.getPayOrderNo())) {
            payOrderDO = payOrderService.queryPayOrder(payOrderQueryReq.getPayOrderNo());
        }
        else {
            String sn = LocalContext.get().getSn();
            payOrderDO = payOrderService.queryPayOrderByMerOrderNo(sn, payOrderQueryReq.getMchOrderNo());
        }
        if (payOrderDO == null) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_NOT_EXIST);
        }
        PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (payOrderStatus) {
            case CLOSE:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_CLOSE);
            case CANCEL:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_CANCEL);
            case SUCCESS:
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_SUCCESS);
            case CLOSEING:
                queryCloseStatus(payOrderDO);
                return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_HAS_CLOSE);
        }
        boolean extensionExist = channelOrderGateway.extensionExist(payOrderDO.getChannelCode());
        if (!extensionExist) {
            return CommonResult.error(CommonResultCode.EXTENSION_NOT_EXIST);
        }
        PayOrderChannelResultDto payOrderChannelResultDto = channelOrderGateway.closeChannelPayOrder(payOrderDO);
        // 非处理成功
        if (!payOrderChannelResultDto.isProcessStatus()) {
            return CommonResult.error(OpenApiResultCode.MERCHANT_PAY_ORDER_OPERATE_FAIL.getCode(), payOrderChannelResultDto.getRemark());
        }
        // 处理成功
        PayOrderDO updartePayOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
        updartePayOrderDO.setId(payOrderDO.getId());
        // String sn = payOrderDO.getSn();
        return CommonResult.success();
    }

    @Override
    public String orderStatusCallBack(String channelCode, String providerCode, HttpServletRequest servletRequest) {
        log.info("orderStatusCallBack start");
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        if (providerChannelConfigDO == null) {
            return processOrderCallBackErrorResponse(channelCode, providerCode, null, null, CommonResult.error(PayResultCode.PROVIDER_CHANNEL_NOT_EXITS));
        }
        CommonResult<PayOrderChannelResultDto> commonResult = channelOrderGateway.orderStatusParse(servletRequest, providerChannelConfigDO);
        log.info("orderStatusCallBack orderStatusParse");
        PayOrderChannelResultDto payOrderChannelResultDto = commonResult.getData();
        if (!commonResult.isSuccess()) {
            if (MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode().equals(commonResult.getCode())) {
                PayOrderDO updatePayOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
                if (updatePayOrderDO != null && StringUtils.hasText(updatePayOrderDO.getPayOrderNo())
                        && PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(updatePayOrderDO.getState())) {
                    PayOrderDO payOrderDO = payOrderService.queryPayOrder(updatePayOrderDO.getPayOrderNo());
                    if (payOrderDO == null) {
                        log.info("收到支付订单回调,签名错误,通过回调订单查询订单数据不存在 payOrderNo:{}", updatePayOrderDO.getPayOrderNo());
                        return commonResult.getMsg();
                    }
                    log.info("收到支付订单回调,签名错误,通过回调订单回查第三方支付状态 payOrderNo:{}", updatePayOrderDO.getPayOrderNo());
                    queryPayStatus(payOrderDO);
                    return processOrderCallBackSuccessResponse(channelCode, payOrderDO, payOrderChannelResultDto.getCallBackBody(), CommonResult.success(),
                            providerChannelConfigDO);
                }
                else {
                    return commonResult.getMsg();
                }
            }
            return commonResult.getMsg();
        }
        return processCallBack(channelCode, payOrderChannelResultDto, providerChannelConfigDO);
    }

    @Override
    public String orderStatusCallBack(String channelCode, HttpServletRequest servletRequest) {
        log.info("orderStatusCallBack start");
        // 获取参数信息
        Map<String, String> params = AliPayApi.toMap(servletRequest);
        if(MapUtil.isNotEmpty(params)){
            // 通知内容文本
            String biz_content = MapUtil.getStr(params,"biz_content");
            // 路由
            switch (channelCode){
                // 支付宝直付通
                case "alipay_zft":
                    if(StrUtil.isNotEmpty(biz_content)){
                        // 通知类型 msg_method -> alipay.trade.order.settle.notify
                        String msg_method = MapUtil.getStr(params,"msg_method");
                        log.info("orderStatusCallBack 支付宝直付通订阅通知 类型 ：{}",msg_method);
                        if(StrUtil.isNotEmpty(msg_method)){
                            switch (msg_method){
                                // 交易分账结果通知
                                case "alipay.trade.order.settle.notify":
                                    AlipayZftDivideNotifyBizContentDto bizContentDto = JSONUtil.toBean(biz_content,AlipayZftDivideNotifyBizContentDto.class);
                                    // 支付宝交易号查询订单信息
                                    PayOrderDO payOrderDO = payOrderService.queryPayOrderByChannelOrderNo(bizContentDto.getTrade_no());
                                    // 支付宝请求号
                                    String out_request_no = bizContentDto.getOut_request_no();
                                    log.info("orderStatusCallBack 支付宝直付通 交易分账结果通知内容 ：{}",biz_content);
                                    return diviceOrderCallBack("alipay_zft",payOrderDO.getProviderCode(),out_request_no,servletRequest);

                                // 商户交易投诉通知
                                case "alipay.security.risk.complaints.merchants.notify":
                                    AliComplaintNotifyResp aliComplaintNotifyResp = JSONUtil.toBean(biz_content,AliComplaintNotifyResp.class);
                                    OrderComplaintDO complaintDO = orderComplaintService.queryDetailByComplaintId(aliComplaintNotifyResp.getComplaint_id());
                                    if(complaintDO != null){
                                        log.info("orderStatusCallBack 支付宝直付通 商户交易投诉通知 ：{}",biz_content);
                                        return complaintOrderAppService.complaintCallBack(complaintDO.getChannelId(), servletRequest);
                                    }else{
                                        log.info("orderStatusCallBack 支付宝直付通 商户交易投诉通知解析失败 未查询到投诉记录 ：{}",biz_content);
                                    }
                                default:
                                    return processOrderCallBackSuccessResponse(channelCode, null, JSONUtil.toJsonStr(params), CommonResult.success(), null);
                            }
                        }else{
                            return processOrderCallBackSuccessResponse(channelCode, null, JSONUtil.toJsonStr(params), CommonResult.success(), null);
                        }
                    }
                    break;
            }
        }

        // 获取通道配置
        CommonResult<PayOrderChannelResultDto> commonResult = channelOrderGateway.orderStatusParse(channelCode, servletRequest);
        PayOrderChannelResultDto payOrderChannelResultDto = commonResult.getData();
        if (!commonResult.isSuccess()) {
            if (MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode().equals(commonResult.getCode())) {
                PayOrderDO updatePayOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
                if (updatePayOrderDO != null && StringUtils.hasText(updatePayOrderDO.getPayOrderNo())
                        && PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(updatePayOrderDO.getState())) {
                    PayOrderDO payOrderDO = payOrderService.queryPayOrder(updatePayOrderDO.getPayOrderNo());
                    if (payOrderDO == null) {
                        log.info("收到支付订单回调,签名错误,通过回调订单查询订单数据不存在payOrderNo:{}", updatePayOrderDO.getPayOrderNo());
                        return commonResult.getMsg();
                    }
                    queryPayStatus(payOrderDO);
                    return processOrderCallBackSuccessResponse(channelCode, payOrderDO, payOrderChannelResultDto.getCallBackBody(), CommonResult.success(), null);
                }
                else {
                    return commonResult.getMsg();
                }
            }
            return commonResult.getMsg();
        }
        return processCallBack(channelCode, payOrderChannelResultDto, null);
    }

    @Override
    public String merAuthStatusCallBack(String channelCode,HttpServletRequest request) {
        CommonResult<PayOrderChannelResultDto> commonResult = channelOrderGateway.merAuthParse(request,channelCode);
        return commonChannelCallHandler.processPayLogAndResponse(channelCode, null, null, null, commonResult);
    }

    @Override
    public String mchOrderStatusCallBack(String channelCode, String providerCode,String mchChannelCode, HttpServletRequest request) {
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = new ProviderChannelConfigDO();
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(mchChannelCode);
        if(merchantAppChannelDO != null){
            providerChannelConfigDO.setParamsConfig(merchantAppChannelDO.getAppConfigJson());
            providerChannelConfigDO.setChannelCode(channelCode);
        }else{
            providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        }
        CommonResult<PayOrderChannelResultDto> commonResult = channelOrderGateway.orderStatusParse(request, providerChannelConfigDO);
        PayOrderChannelResultDto payOrderChannelResultDto = commonResult.getData();
        if (!commonResult.isSuccess()) {
            if (MerchantResultCode.MERCHANT_CHANNEL_CALLBACK_SIGN_ERROR.getCode().equals(commonResult.getCode())) {
                PayOrderDO updatePayOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
                if (updatePayOrderDO != null && StringUtils.hasText(updatePayOrderDO.getPayOrderNo())
                        && PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(updatePayOrderDO.getState())) {
                    PayOrderDO payOrderDO = payOrderService.queryPayOrder(updatePayOrderDO.getPayOrderNo());
                    if (payOrderDO == null) {
                        log.info("收到支付订单回调,签名错误,通过回调订单查询订单数据不存在 payOrderNo:{}", updatePayOrderDO.getPayOrderNo());
                        return commonResult.getMsg();
                    }
                    log.info("收到支付订单回调,签名错误,通过回调订单回查第三方支付状态 payOrderNo:{}", updatePayOrderDO.getPayOrderNo());
                    queryPayStatus(payOrderDO);
                    return processOrderCallBackSuccessResponse(channelCode, payOrderDO, payOrderChannelResultDto.getCallBackBody(), CommonResult.success(),
                            providerChannelConfigDO);
                }
                else {
                    return commonResult.getMsg();
                }
            }
            return commonResult.getMsg();
        }
        return processCallBack(channelCode, payOrderChannelResultDto, providerChannelConfigDO);
    }

    @Override
    public String closeOrderCallBack(String channelCode, String providerCode, HttpServletRequest accessCallBody) {
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        if (providerChannelConfigDO == null) {
            return commonChannelCallHandler.processAccessLogAndResponse(channelCode, providerCode, null, null, null, null,
                    CommonResult.error(PayResultCode.PROVIDER_CHANNEL_NOT_EXITS));
        }
        PayOrderDO payOrderDO = channelOrderGateway.closeOrderStatusParse(accessCallBody, providerChannelConfigDO);
        PayOrderChannelResultDto payOrderChannelResultDto = new PayOrderChannelResultDto();
        payOrderChannelResultDto.setUpdatePayOrderDO(payOrderDO);
        return processCallBack(channelCode, payOrderChannelResultDto, providerChannelConfigDO);
    }

    @Override
    public String closeOrderCallBack(String channelCode, String providerCode, String mchChannelCode, HttpServletRequest request) {
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = new ProviderChannelConfigDO();
        MerchantAppChannelDO merchantAppChannelDO = merchantApplicationService.queryAppChannelDetail(mchChannelCode);
        if(merchantAppChannelDO != null){
            providerChannelConfigDO.setParamsConfig(merchantAppChannelDO.getAppConfigJson());
            providerChannelConfigDO.setChannelCode(channelCode);
        }else{
            providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        }
        PayOrderDO payOrderDO = channelOrderGateway.closeOrderStatusParse(request, providerChannelConfigDO);
        PayOrderChannelResultDto payOrderChannelResultDto = new PayOrderChannelResultDto();
        payOrderChannelResultDto.setUpdatePayOrderDO(payOrderDO);
        return processCallBack(channelCode, payOrderChannelResultDto, providerChannelConfigDO);
    }

    @Override
    public String csOrderCallBack(String channelCode, String providerCode, HttpServletRequest request) {
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        if (providerChannelConfigDO == null) {
            return commonChannelCallHandler.processAccessLogAndResponse(channelCode, providerCode, null, null, null, null,
                    CommonResult.error(PayResultCode.PROVIDER_CHANNEL_NOT_EXITS));
        }
        CommonResult<CsOrderNotifyDto> commonResult = channelOrderGateway.csOrderStatusParse(request, providerChannelConfigDO);
        if(!commonResult.isSuccess()){
            commonChannelCallHandler.processCsOrderLogAndResponse(channelCode, CommonResult.error(CommonResultCode.DATA_NOT_EFFECT));
        }

        CsOrderNotifyDto csOrderNotifyDto = commonResult.getData();
        PayOrderDO payOrderDO = csOrderNotifyDto.getPayOrderDO();
        if (payOrderDO == null || !StringUtils.hasText(payOrderDO.getPayOrderNo())) {
            return processOrderCallBackErrorResponse(channelCode, null, null, null,
                    CommonResult.error(CommonResultCode.PARAMETER_MISSING));
        }
        PayOrderDO orderDb = payOrderService.queryPayOrder(payOrderDO.getPayOrderNo());
        if (orderDb == null) {
            return processOrderCallBackErrorResponse(channelCode, null, null, null,
                    CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_NOT_EXIST));
        }
        // 更新数据
        payOrderDO.setId(orderDb.getId());
        payOrderService.updatePayOrder(payOrderDO,orderDb.getPayOrderNo(),orderDb.getSn(),orderDb.getMchOrderNo());
        return  commonChannelCallHandler.processPayLogAndResponse(channelCode, null, null, null, CommonResult.success());
    }

    @Override
    public String diviceOrderCallBack(String channelCode, String providerCode, String batchNo,HttpServletRequest request) {
        log.info("diviceOrderCallBack start");
        // 获取通道配置
        ProviderChannelConfigDO providerChannelConfigDO = providerService.queryConfig(providerCode, channelCode);
        if (providerChannelConfigDO == null) {
            return commonChannelCallHandler.processAccessLogAndResponse(channelCode, providerCode, null, null, null, null,
                    CommonResult.error(PayResultCode.PROVIDER_CHANNEL_NOT_EXITS));
        }

        ChannelProfitOrderContext channelProfitOrderContext = new ChannelProfitOrderContext();
        channelProfitOrderContext.setProviderChannelConfig(providerChannelConfigDO);
        // 批次号查询分账订单
        OrderFundDto orderFundDto = payOrderFundService.queryAcctOrderFundDto(batchNo);
        if(orderFundDto == null){
            return commonChannelCallHandler.processAccessLogAndResponse(channelCode, providerCode, null, null, null, null,
                    CommonResult.error(CommonResultCode.DATA_NOT_EXIST));
        }
        log.info("diviceOrderCallBack query time");
        channelProfitOrderContext.setOrderFundDO(orderFundDto.getOrderFund());
        channelProfitOrderContext.setOrderFundDetailDOList(orderFundDto.getOrderFundDetailList());
        CommonResult<String> commonResult = channelProfitOrderGateway.acctStatusParse(request, channelProfitOrderContext);
        log.info("diviceOrderCallBack acctStatusParse time");
        if(!commonResult.isSuccess()){
            return commonChannelCallHandler.processDivideOrderLogAndResponse(channelCode, CommonResult.error(CommonResultCode.DATA_NOT_EFFECT));
        }

        if(channelProfitOrderContext.getPayOrderFundStatus() != null){
            payOrderFundService.updatePayFundStatus(orderFundDto.getOrderFund().getId(),channelProfitOrderContext.getPayOrderFundStatus());
        }
        if(CollUtil.isNotEmpty(channelProfitOrderContext.getOrderFundDetailDOList())){
            payOrderFundService.updatePayFundDetails(channelProfitOrderContext.getOrderFundDetailDOList());
        }
        log.info("diviceOrderCallBack update time");
        return commonChannelCallHandler.processDivideOrderLogAndResponse(channelCode, CommonResult.success());
    }

    @Override
    public void processOrderStatusQuery(OrderStatusDto orderStatusDto, boolean system) {
        PayOrderEnums.ORDER_STATUS_TYPE orderStatusType = PayOrderEnums.ORDER_STATUS_TYPE.from(orderStatusDto.getOrderStatusType());
        boolean needSend = false;
        String orderNo = orderStatusDto.getOrderNo();
        if (!StringUtils.hasText(orderNo)) {
            log.info("收到的数据错误 orderNo:{}", orderNo);
            return;
        }
        switch (orderStatusType) {
            case PAY_ORDER_STATUS:
                PayOrderDO payOrderDO = payOrderService.queryPayOrder(orderNo);
                if (payOrderDO == null) {
                    log.info("收到的数据错误 订单号不存在 orderNo:{}", orderNo);
                    return;
                }
                needSend = queryOrderStatus(payOrderDO, orderStatusDto.getTotalConsumerCount());
                break;
            case REFUND_STATUS:
                needSend = refundOrderAppService.queryRefundStatus(orderNo);
                break;
            case ORDER_CLOSE:
                payOrderDO = payOrderService.queryPayOrder(orderNo);
                queryCloseStatus(payOrderDO);
                break;
        }
        // 没有查询到结果 重新丢到队列中
        if (needSend && system) {
            if (orderStatusDto.getDelayLevel() == null) {
                orderStatusDto.setDelayLevel(1);
            }
            log.info("当前订单状态未变更,需要重新丢到延迟队列 orderNo:{}", orderNo);
            orderHandler.sendOrderStatus(orderStatusDto);
        }
    }

    @Override
    @Async("taskExecutor")
    public void processOrderStatusQuery(List<PayOrderDO> payOrderList) {
        log.info("订单状态查询");
        payOrderList.stream().forEach(payOrderDO -> {
            queryOrderStatus(payOrderDO, null);
        });
    }

    @Override
    public CommonResult<PrePayOrderResp> queryOrder(String payOrderNo) {
        if (!StringUtils.hasText(payOrderNo)) {
            return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
        }
        PayOrderDO payOrderDO = null;
        payOrderDO = payOrderService.queryPayOrder(payOrderNo);
        if (payOrderDO == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_NOT_EXIST);
        }
        queryPayStatus(payOrderDO);
        PayOrderResp payOrderResp = PayOrderDoToResp.INSTANCE.payOrderResp(payOrderDO);

        PrePayOrderResp prePayOrderResp = BeanUtil.copyProperties(payOrderResp, PrePayOrderResp.class);
        CommonAppDO commonAppDO = channelOrderGateway.queryChannelPayAppid(payOrderDO);
        if (commonAppDO != null) {
            prePayOrderResp.setAppId(commonAppDO.getAppId());
        }
        return CommonResult.success(prePayOrderResp);
    }

    @Override
    public CommonResult<String> queryRedirectUrl(String payOrderNo) {
        PayOrderDO payOrderDO = payOrderService.queryPayOrder(payOrderNo);
        if (payOrderDO == null) {
            return CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_NOT_EXIST);
        }
        if (StringUtils.hasText(payOrderDO.getRedirectUrl()))
            return CommonResult.success(payOrderDO.getRedirectUrl());
        else
            return CommonResult.success(defaultRedirectUrl);
    }

    boolean queryOrderStatus(PayOrderDO payOrderDO, Integer delayConsumerCount) {
        PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (payOrderStatus) {
            case INIT:
            case PAYING:
                Long expiredTime = payOrderDO.getExpiredTime();
                if (expiredTime == null) {
                    expiredTime = payOrderDO.getCreateTime() + OrderConstant.EXPIRE_TIME;
                }
                boolean closeOrderStatus = false;
                boolean queryOrderStatus = false;
                // 当前时间小于失效时间,才查询订单状态
                if (System.currentTimeMillis() < expiredTime) {
                    queryOrderStatus = queryPayStatus(payOrderDO);
                    // 消费次数过多 关闭订单
                    if (queryOrderStatus && delayConsumerCount != null && delayConsumerCount > orderDelayConsumerCount) {
                        closeOrderStatus = true;
                    }
                }
                else {
                    log.info("支付订单 当前订单已超过失效时间,直接关闭 mchOrderNo:{}", payOrderDO.getMchOrderNo());
                    closeOrderStatus = true;
                }
                if (closeOrderStatus) {
                    if (payOrderDO.getExpiredTime() == null) {
                        payOrderDO.setExpiredTime(expiredTime);
                    }
                    payOrderService.closePayOrder(payOrderDO);
                    // 调用第三方关闭订单
                    channelOrderGateway.closeChannelPayOrder(payOrderDO);
                    return false;
                }
                return queryOrderStatus;
            case CLOSEING:
                queryCloseStatus(payOrderDO);
                break;
        }
        return false;
    }

    /**
     * 支付状态查询
     *
     * @param payOrderDO
     * @return
     */
    boolean queryPayStatus(PayOrderDO payOrderDO) {
        log.info("支付订单 查询支付中状态 mchOrderNo:{},state:{}", payOrderDO.getMchOrderNo(), payOrderDO.getState());
        PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (payOrderStatus) {
            case PAYING:
                boolean extensionExist = channelOrderGateway.extensionExist(payOrderDO.getChannelCode());
                if (extensionExist) {
                    PayOrderChannelResultDto payOrderChannelResultDto = channelOrderGateway.queryChannelPayOrder(payOrderDO);
                    PayOrderDO updartePayOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
                    if (updartePayOrderDO != null && updartePayOrderDO.getState() != null) {
                        // 二者数据不一致 需要更新数据
                        if (!updartePayOrderDO.getState().equals(payOrderDO.getState())) {
                            // 更新后的熟悉进行复制
                            payOrderDO.setInsOrderNo(updartePayOrderDO.getInsOrderNo());
                            payOrderDO.setAtuSubMerId(updartePayOrderDO.getAtuSubMerId());
                            payOrderDO.setSettlementAmount(updartePayOrderDO.getSettlementAmount());
                            payOrderDO.setSuccessTime(updartePayOrderDO.getSuccessTime());
                            payOrderDO.setPayAmount(updartePayOrderDO.getPayAmount());
                            payOrderDO.setState(updartePayOrderDO.getState());
                            if (StringUtils.hasText(updartePayOrderDO.getBankMsg())) {
                                payOrderDO.setBankMsg(updartePayOrderDO.getBankMsg());
                            }
                            updatePayOrder(updartePayOrderDO, payOrderDO);
                            return false;
                        }
                    }
                    else {
                        return true;
                    }
                    break;
                }
                else {
                    log.info("支付订单 当前通道不支持渠道订单功能 channelCode:{}", payOrderDO.getChannelCode());
                    return false;
                }

        }
        return false;
    }

    /**
     * 支付状态查询
     *
     * @param payOrderDO
     * @return
     */
    boolean queryCloseStatus(PayOrderDO payOrderDO) {
        log.info("支付订单 查询关闭中状态 mchOrderNo:{},state:{}", payOrderDO.getMchOrderNo(), payOrderDO.getState());
        PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (payOrderStatus) {
            case CLOSEING:
                boolean extensionExist = channelOrderGateway.extensionExist(payOrderDO.getChannelCode());
                if (extensionExist) {
                    PayOrderChannelResultDto payOrderChannelResultDto = channelOrderGateway.queryChannelCloseOrder(payOrderDO);
                    PayOrderDO updartePayOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
                    if (updartePayOrderDO != null) {
                        // 二者数据不一致 需要更新数据
                        if (!updartePayOrderDO.getState().equals(payOrderDO.getState())) {
                            updatePayOrder(updartePayOrderDO, payOrderDO);
                            // 更新后的熟悉进行复制
                            payOrderDO.setState(updartePayOrderDO.getState());
                            return false;
                        }
                    }
                    else {
                        return true;
                    }
                    break;
                }
                else {
                    log.info("支付订单 当前通道不支持渠道订单功能 channelCode:{}", payOrderDO.getChannelCode());
                    return false;
                }
        }
        return false;
    }

    String processOrderCallBackSuccessResponse(String channelCode, PayOrderDO payOrderDO, String callBackBody, CommonResult commonResult,
            ProviderChannelConfigDO providerChannelConfigDO) {
        commonResult.setData(providerChannelConfigDO);
        if (payOrderDO != null) {
            LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
            localMerchantRequest.setProviderCode(payOrderDO.getProviderCode());
            localMerchantRequest.setChannelCode(payOrderDO.getChannelCode());
            localMerchantRequest.setMchChannelCode(payOrderDO.getMchChannelCode());
            localMerchantRequest.setSn(payOrderDO.getOrderSn());
            localMerchantRequest.setAppId(payOrderDO.getAppId());
            LocalContext.set(localMerchantRequest);
            return commonChannelCallHandler.processPayLogAndResponse(channelCode, payOrderDO.getProviderCode(), payOrderDO.getPayOrderNo(), callBackBody, commonResult);
        }
        return commonChannelCallHandler.processPayLogAndResponse(channelCode, null, null, callBackBody, commonResult);
    }

    String processOrderCallBackErrorResponse(String channelCode, String providerCode, String requestId, String callBackBody, CommonResult commonResult) {
        return commonChannelCallHandler.processPayLogAndResponse(channelCode, providerCode, requestId, callBackBody, commonResult);
    }

    String processCallBack(String channelCode, PayOrderChannelResultDto payOrderChannelResultDto, ProviderChannelConfigDO providerChannelConfigDO) {
        log.info("{} processCallBack start",channelCode);
        PayOrderDO payOrderDO = payOrderChannelResultDto.getUpdatePayOrderDO();
        if (payOrderDO == null || !StringUtils.hasText(payOrderDO.getPayOrderNo()) || payOrderDO.getState() == null) {
            return processOrderCallBackErrorResponse(channelCode, payOrderDO.getProviderCode(), payOrderDO.getPayOrderNo(), payOrderChannelResultDto.getCallBackBody(),
                    CommonResult.error(CommonResultCode.PARAMETER_MISSING));
        }
        PayOrderDO orderDb = payOrderService.queryPayOrder(payOrderDO.getPayOrderNo());
        if (orderDb == null) {
            return processOrderCallBackErrorResponse(channelCode, payOrderDO.getProviderCode(), payOrderDO.getPayOrderNo(), payOrderChannelResultDto.getCallBackBody(),
                    CommonResult.error(MerchantResultCode.MERCHANT_PAY_ORDER_NOT_EXIST));
        }
        log.info("{} processCallBack queryPayOrder",channelCode);
        if(orderDb.getState().equals(payOrderDO.getState())){
            log.info("收到支付订单回调,订单实际状态与 回调状态一致 直接返回 payOrderNo:{}", payOrderDO.getPayOrderNo());
            return processOrderCallBackSuccessResponse(channelCode, orderDb, payOrderChannelResultDto.getCallBackBody(), CommonResult.success(), providerChannelConfigDO);
        }
        if (payOrderDO.getSuccessTime() == null) {
            payOrderDO.setSuccessTime(System.currentTimeMillis());
        }
        if (payOrderDO.getPayAmount() == null) {
            payOrderDO.setPayAmount(orderDb.getAmount());
        }
        // 更新数据
        updatePayOrder(payOrderDO, orderDb);
        log.info("{} processCallBack updatePayOrder",channelCode);
        if (!CollectionUtils.isEmpty(payOrderChannelResultDto.getOrderFunds())) {
            payOrderFundService.updateAcctInfoCallBack(orderDb, payOrderChannelResultDto.getOrderFunds());
            log.info("{} processCallBack updateAcctInfoCallBack",channelCode);
        }
        return processOrderCallBackSuccessResponse(channelCode, orderDb, payOrderChannelResultDto.getCallBackBody(), CommonResult.success(), providerChannelConfigDO);
    }

    PayOrderDO buildPayOrder(PayWayDO payWayDO, MerchantAppChannelDO merchantAppChannelDO, PayOrderParamReq payOrderParamReq, String payOrderNo, String orderSn,
            BigDecimal commRateBase, BigDecimal feeAmount) {
        LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
        PayOrderDO payOrderDO = new PayOrderDO();
        payOrderDO.setPayOrderNo(payOrderNo);
        payOrderDO.setMchOrderNo(payOrderParamReq.getMchOrderNo());
        // payOrderDO.setInsOrderNo();
        // payOrderDO.setChannelOrderNo();
        // payOrderDO.setChannelOrderId();
        payOrderDO.setMchChannelCode(merchantAppChannelDO.getCode());
        payOrderDO.setSubMchId(merchantAppChannelDO.getSubMchId());
        payOrderDO.setPayType(payOrderParamReq.getPayType());
        payOrderDO.setPaySubType(payOrderParamReq.getPaySubType());
        payOrderDO.setSceneType(payOrderParamReq.getSceneType());
        payOrderDO.setPayWayCode(payWayDO.getCode());
        payOrderDO.setAmount(new BigDecimal(payOrderParamReq.getAmount()));
        payOrderDO.setClientIp(payOrderParamReq.getClientIp());
        payOrderDO.setSubject(payOrderParamReq.getSubject());
        payOrderDO.setDescription(payOrderParamReq.getDescription());
        if (payOrderParamReq.getExtra() != null) {
            payOrderDO.setExtra(JsonUtils.toJsonString(payOrderParamReq.getExtra()));
        }
        // 采集信息
        if(StrUtil.isNotEmpty(payOrderParamReq.getColletJson())){
            payOrderDO.setColletJson(payOrderParamReq.getColletJson());
        }
        // 订单备注
        if(StrUtil.isNotEmpty(payOrderParamReq.getRemark())){
            payOrderDO.setRemark(payOrderParamReq.getRemark());
        }
        payOrderDO.setNotifyUrl(payOrderParamReq.getNotifyUrl());
        payOrderDO.setRedirectUrl(payOrderParamReq.getRedirectUrl());
        payOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.INIT.getCode());
        int expiredTime = payOrderParamReq.getExpiredTime() != null ? payOrderParamReq.getExpiredTime() : 30 * 60;
        payOrderDO.setExpiredTime(System.currentTimeMillis() + expiredTime * 1000);
        // payOrderDO.setSuccessTime();
        // payOrderDO.setBankCode();
        // payOrderDO.setBankMsg();
        payOrderDO.setSn(localMerchantRequest.getSn());

        payOrderDO.setOrderSn(orderSn);
        payOrderDO.setAppId(merchantAppChannelDO.getAppId());
        payOrderDO.setProviderCode(merchantAppChannelDO.getProviderCode());
        payOrderDO.setChannelCode(merchantAppChannelDO.getChannelCode());
        payOrderDO.setChannelConfig(merchantAppChannelDO.getAppConfigJson());
        payOrderDO.setFeeAmount(feeAmount);
        // payOrderDO.setChannelFeeAmount();
        // payOrderDO.setSettlementAmount();
        payOrderDO.setFeeRate(commRateBase);
        // payOrderDO.setChannelFeeRate();
        payOrderDO.setNotifyState(CommonEnum.YES_NO_TYPE.NO.getCode());
        // payOrderDO.setFeeTime();
        // payOrderDO.setNotifyTime();
        // payOrderDO.setUserId();
        payOrderDO.setRefundStatus(PayOrderEnums.ORDER_REFUND_STATUS.NO_REFUND.getCode());
        payOrderDO.setRefundAmount(new BigDecimal(0));
        if (payOrderParamReq.getFundProcessType() == null) {
            payOrderDO.setFundProcessType(PayOrderEnums.FUND_PROCESS_TYPE.NO.getCode());
        }
        else {
            payOrderDO.setFundProcessType(payOrderParamReq.getFundProcessType());
        }
        // payOrderDO.setOrderSplitAmount();
        payOrderDO.setSignType(localMerchantRequest.getSignType());
        // payOrderDO.setAtuSubMerId();
        if (!CollectionUtils.isEmpty(payOrderParamReq.getAcctInfos())) {
            payOrderDO.setAcctInfoJson(JsonUtils.toJsonString(payOrderParamReq.getAcctInfos()));
        }
        if (payOrderParamReq.getOrderType() == null) {
            payOrderDO.setOrderType(PayOrderEnums.PAY_ORDER_TYPE.MERCHANT.getCode());
        }
        else {
            payOrderDO.setOrderType(payOrderParamReq.getOrderType().getCode());
            payOrderDO.setRelationOrderNo(payOrderParamReq.getRelationOrderNo());
        }
        return payOrderDO;
    }

    PayOrderSubmitApiResp buildThirdOrderParams(PayOrderDO payOrderDO, PayOrderChannelResultDto payOrderChannelResultDto) {
        // 部分场景没有直接调用第三方 所有没有返回对应的第三方订单号
        PayOrderSubmitApiResp payOrderResp = PayOrderDoToResp.INSTANCE.payOrderSubmitResp(payOrderDO);
        // if (!StringUtils.hasText(payOrderChannelResultDto.getChannelOrderNo())) {
        // return payOrderResp;
        // }
        if (StringUtils.hasText(payOrderChannelResultDto.getInsOrderNo())) {
            payOrderDO.setInsOrderNo(payOrderChannelResultDto.getInsOrderNo());
        }

        if (StringUtils.hasText(payOrderChannelResultDto.getAutCode())) {
            payOrderDO.setAutCode(payOrderChannelResultDto.getAutCode());
        }

        if (StringUtils.hasText(payOrderChannelResultDto.getAutSubMerId())) {
            payOrderDO.setAtuSubMerId(payOrderChannelResultDto.getAutSubMerId());
        }

        if (payOrderChannelResultDto.isRequestThird()) {
            payOrderDO.setChannelOrderNo(payOrderChannelResultDto.getChannelOrderNo());
            payOrderDO.setChannelOrderId(payOrderChannelResultDto.getChannelOrderId());
            payOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
        }
        else {
            payOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.INIT.getCode());
        }
        if (payOrderChannelResultDto.getExtra() != null) {
            payOrderDO.setExtra(JsonUtils.toJsonStringNotNull(payOrderChannelResultDto.getExtra()));
        }
        payOrderResp.setPayInfo(payOrderChannelResultDto.getPayInfo());
        payOrderResp.setPayDataType(payOrderChannelResultDto.getPayDataType());
        return payOrderResp;
    }

    PayOrderDO buildPreThirdOrderParams(PayOrderDO payOrderDO, PayOrderChannelResultDto payOrderChannelResultDto) {
        // PayOrderDO payOrderDO = payOrderChannelResultDto.getPayOrderDO();
        PayOrderDO updatePayOrderDO = new PayOrderDO();
        updatePayOrderDO.setId(payOrderDO.getId());
        // payOrderDO.setInsOrderNo(payOrderChannelResultDto.get);
        updatePayOrderDO.setChannelOrderNo(payOrderChannelResultDto.getChannelOrderNo());
        updatePayOrderDO.setChannelOrderId(payOrderChannelResultDto.getChannelOrderId());
        updatePayOrderDO.setInsOrderNo(payOrderDO.getInsOrderNo());
        updatePayOrderDO.setPayInfo(payOrderChannelResultDto.getPayInfo());
        updatePayOrderDO.setPayDataType(payOrderChannelResultDto.getPayDataType());
        updatePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
        if (payOrderChannelResultDto.getExtra() != null) {
            updatePayOrderDO.setExtra(JsonUtils.toJsonStringNotNull(payOrderChannelResultDto.getExtra()));
        }
        return updatePayOrderDO;
    }

    void updatePayOrder(PayOrderDO updartePayOrderDO, PayOrderDO payOrderDO) {
        updartePayOrderDO.setId(payOrderDO.getId());
        int count = payOrderService.updatePayOrderStatus(updartePayOrderDO, payOrderDO.getPayOrderNo(), payOrderDO.getSn(), payOrderDO.getMchOrderNo());
        log.info("{} updatePayOrder start",payOrderDO.getChannelCode());
        // 下发状态变更通知
        if (count > 0) {
            if (PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode().equals(updartePayOrderDO.getState())) {
                // 数据有更新 重新获取一次
                payOrderDO = payOrderService.queryPayOrder(payOrderDO.getPayOrderNo());
                // 统计数据
                orderHandler.payOrder(payOrderDO);
                log.info("{} updatePayOrder orderHandler",payOrderDO.getChannelCode());
            }
        }
        else {
            log.info("支付订单 更新订单状态,数据库返回更新的状态与原数据状态一致 直接返回 payOrderNo:{}", payOrderDO.getPayOrderNo());
        }
    }

}
